package main

import (
	"net/http"
	"strconv"
	"strings"

	"net/http/pprof"

	"github.com/gin-gonic/gin" // gin-swagger middleware
	"google.golang.org/protobuf/proto"
	"smeb.xyz/pub/websocket-subandpub-cluster/internal/handlerwebsocket/docs"
	protos "smeb.xyz/pub/websocket-subandpub-cluster/internal/handlerwebsocket/protos"
)

func InitWebServer() {
	// programmatically set swagger info
	docs.SwaggerInfo.Title = "WS_SERVER_Clusters API"
	docs.SwaggerInfo.Description = "This is a WS_SERVER_Clusters API Doc."
	docs.SwaggerInfo.Version = "1.0"
	docs.SwaggerInfo.Host = "127.0.0.1:8080"
	docs.SwaggerInfo.BasePath = "/"
	docs.SwaggerInfo.Schemes = []string{"http"}
	Gin = gin.Default()
	channel := Gin.Group("/channel")
	{
		channel.POST("/CreateNewChannel", CreateNewChannel)
		channel.DELETE("/DeleteChannel", DeleteChannel)
		channel.GET("/GetChannelConnCount", GetChannelConnCount)
		channel.DELETE("/DeleteChannelMembers", DeleteChannelMembers)
		channel.POST("/PublishToChannel", PublishToChannel)
		channel.POST("/PublishToSomeoneInChannel", PublishToSomeoneInChannel)
		channel.POST("/PublishToSomebodyInChannel", PublishToSomebodyInChannel)
		// Gin.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
		channel.POST("MultipleIdentitySubscribleChannel", MultipleIdentitySubscribleChannel)
	}

	manage := Gin.Group("/manage").Use(AuthRequired())
	{
		manage.GET("/GetStatistical", GetStatistical)
		manage.GET("/GetCluserList", GetCluserList)
		manage.GET("/GetClusterInfo", GetClusterInfo)
		manage.GET("/GetChannels", GetChannels)
		manage.GET("/GetChannelsCount", GetChannelsCount)
	}

	Gin.GET("/debug/pprof/*any", gin.WrapH(http.HandlerFunc(pprof.Index)))

	fs := http.FileSystem(http.Dir("/smebxyz/golang/websocket-cluster/internal/handlerwebsocket/admin/"))

	// 创建一个新的Gin路由组，将Flutter Web应用程序作为子应用
	flutterApp := Gin.Group("/admin").Use(AuthRequired())
	{
		flutterApp.StaticFS("/", fs)
	}

	Gin.Run(":" + strconv.Itoa(Configs.WebPort))
}

// 认证中间件
func AuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Header("Access-Control-Allow-Origin", "*")
		c.Next()
	}
}

// 新增频道 godoc
// @Summary      新增频道
// @Description  新增频道
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /CreateNewChannel [post]

func CreateNewChannel(c *gin.Context) {
	channelid := GetRandomString(36)
	ii, ee := Redis.SAdd(c, channelid, []string{"const"}).Result()
	if ee != nil || ii == 0 {
		c.JSON(500, gin.H{
			"message": "创建频道失败",
		})
		return
	}
	Redis.SAdd(c, Channel_Redis_key, channelid).Result()
	c.JSON(200, gin.H{
		"message": "已创建该频道",
		"data":    channelid,
	})

}

// 删除频道 godoc
// @Summary      删除频道
// @Description  删除频道
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        channel query string true "频道Id"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /DeleteChannel [delete]
func DeleteChannel(c *gin.Context) {
	channel := c.Query("channel")
	i, e := Redis.Del(c, channel).Result()
	if e != nil || i == 0 {
		c.JSON(200, gin.H{
			"message": "success",
		})
	} else {
		servers, b := Redis.SMembers(c, channel).Result()
		if b == nil {
			for _, server := range servers {
				RpcOnChannelDeleted(server, &protos.DeleteChannelRequest{
					Channel: channel,
				})
			}
			Redis.SRem(c, Channel_Redis_key, channel).Result()
			c.JSON(200, gin.H{
				"message": "success",
			})
			return

		} else {
			c.JSON(500, gin.H{
				"message": "删除频道失败",
			})
			return
		}
	}
}

// 获取频道在线人数 godoc
// @Summary      获取频道在线人数
// @Description  获取频道在线人数
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        channel query string true "频道Id"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /GetChannelConnCount [get]
func GetChannelConnCount(c *gin.Context) {
	channel := c.Query("channel")
	data, e := Redis.SCard(c, channel).Result()
	if e != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	}
	c.JSON(200, gin.H{
		"message": "success",
		"data":    data,
	})
}

// 删除频道成员 godoc ?????
// @Summary      删除频道成员
// @Description  删除频道成员
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        channel formData string true "频道Id"
// @Param        identitys formData string true "用户Id"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /DeleteChannelMembers [delete]
func DeleteChannelMembers(c *gin.Context) {
	deletejson := DeleteChannelMemberStruct{}
	c.BindJSON(&deletejson)

	servers, b := Redis.SMembers(c, deletejson.Channel).Result()

	var membersList []uint64
	for _, member := range strings.Split(deletejson.Identitys, ",") {
		i, _ := strconv.ParseUint(member, 10, 64)
		membersList = append(membersList, i)
	}

	if b == nil {
		for _, server := range servers {
			RpcDeleteChannelMembers(server, &protos.DeleteChannelMembersRequest{
				Channel: deletejson.Channel,
				Members: membersList,
			})
		}
	}
	c.JSON(200, gin.H{
		"message": "success",
	})
}

// 多个用户订阅一个频道 godoc
// @Summary      多个用户订阅一个频道
// @Description  多个用户订阅一个频道
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        channel formData string true "频道Id"
// @Param        identitys formData string true "用户Id"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /MultipleIdentitySubscribleChannel [post]
func MultipleIdentitySubscribleChannel(c *gin.Context) {

	channel := c.PostForm("channel")
	members := c.PostForm("identitys")

	membersInfo := strings.Split(members, ",")

	var membersList []uint64

	for _, member := range membersInfo {
		i, _ := strconv.ParseUint(member, 10, 64)
		membersList = append(membersList, i)
	}

	for _, member := range membersInfo {
		memberInfo, e := Redis.Get(c, member).Result()
		if e == nil {
			i := strings.Split(memberInfo, "-")
			RpcMultiUserSubscribleChannel(i[0], &protos.MultipleIdentitySubscribleChannelRequest{
				Channel: channel,
				Members: membersList,
			})
		}
	}

	c.JSON(200, gin.H{
		"message": "success",
	})
}

// 发布消息到频道 godoc
// @Summary      发布消息到频道
// @Description  发布消息到频道
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        offline query string true "是否离线发送"
// @Param        ser_msg formData protos.SerializableMessage true "消息内容"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /PublishToChannel [post]
func PublishToChannel(c *gin.Context) {
	var ser_msg protos.MessageProtoBuf
	err := c.BindJSON(&ser_msg)
	if err != nil {
		c.JSON(500, gin.H{
			"message": "json序列化失败",
		})
		return
	}
	suc, err := Redis.SMembers(c, ser_msg.Channel).Result()
	if err != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	}

	ser_msg.Id, ser_msg.Timestamp = GenerateMessageId(ZapLogger)
	data, err := proto.Marshal(&ser_msg)
	if err != nil {
		ZapLogger.Fatal("marshaling error: ", err)
	}
	// 在线发送
	AddOneTaskToQueue(Job{
		Channel:          &ser_msg.Channel,
		Data:             &data,
		ChannelSubServer: &suc,
		Sender:           &ser_msg.Sender,
	})

	c.JSON(200, gin.H{
		"message":   "success",
		"data":      ser_msg.Id,
		"timestamp": ser_msg.Timestamp,
	})
}

// 发布消息给频道中某些人 godoc
// @Summary      发布消息给频道中某些人
// @Description  发布消息给频道中某些人
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        identitys query string true "用户Id,多个用户用逗号分隔"
// @Param        ser_msg formData protos.SerializableMessage true "消息内容"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /PublishToSomeoneInChannel [post]
func PublishToSomeoneInChannel(c *gin.Context) {
	var ser_msg protos.MessageProtoBuf
	err := c.BindJSON(&ser_msg)
	if err != nil {
		c.JSON(500, gin.H{
			"message": "json序列化失败",
		})
		return
	}

	suc, err := Redis.SMembers(c, ser_msg.Channel).Result()
	if err != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	}

	ser_msg.Id, ser_msg.Timestamp = GenerateMessageId(ZapLogger)
	data, err := proto.Marshal(&ser_msg)
	if err != nil {
		ZapLogger.Fatal("marshaling error: ", err)
	}
	AddOneSomeoneTaskToQueue(SomeoneJob{
		Channel:          &ser_msg.Channel,
		Data:             &data,
		ChannelSubServer: &suc,
		Sender:           &ser_msg.Sender,
	})

	c.JSON(200, gin.H{
		"message":   "success",
		"data":      ser_msg.Id,
		"timestamp": ser_msg.Timestamp,
	})
}

// 发布消息给频道中某些人 godoc
// @Summary      发布消息给频道中某些人
// @Description  发布消息给频道中某些人
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        identitys query string true "用户Id,多个用户用逗号分隔"
// @Param        ser_msg formData protos.SerializableMessage true "消息内容"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /PublishToSomebodyInChannel [post]
func PublishToSomebodyInChannel(c *gin.Context) {
	var ser_msg protos.MessageProtoBuf
	err := c.BindJSON(&ser_msg)
	if err != nil {
		c.JSON(500, gin.H{
			"message": "json序列化失败",
		})
		return
	}
	suc, err := Redis.SMembers(c, ser_msg.Channel).Result()
	if err != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	}

	ser_msg.Id, ser_msg.Timestamp = GenerateMessageId(ZapLogger)
	data, err := proto.Marshal(&ser_msg)
	if err != nil {
		ZapLogger.Fatal("marshaling error: ", err)
	}
	AddOneSomebodyTaskToQueue(SomebodyJob{
		Channel:          &ser_msg.Channel,
		Data:             &data,
		ChannelSubServer: &suc,
		Sender:           &ser_msg.Sender,
	})

	c.JSON(200, gin.H{
		"message":   "success",
		"data":      ser_msg.Id,
		"timestamp": ser_msg.Timestamp,
	})
}

// 获取 godoc
// @Summary      获取频道在线人数
// @Description  获取频道在线人数
// @Tags         WebSocket
// @Accept       json
// @Produce      json
// @Param        channel query string true "频道Id"
// @Success      200  {object} 		map[string]interface{}
// @Failure      500  {object}   map[string]interface{}
// @Router       /GetStatistical [get]
func GetStatistical(c *gin.Context) {

	cluster := Redis.SCard(c, "wsserver").Val()
	conn := Redis.SCard(c, ConnId_Redix_key).Val()
	channel := Redis.SCard(c, Channel_Redis_key).Val()
	s := protos.GetStatisticalResponse{
		Cluster: cluster,
		Conn:    conn,
		Channel: channel,
	}
	c.JSON(200, &s)
}

func GetCluserList(c *gin.Context) {
	s, e := Redis.SMembers(c, "wsserver").Result()
	if e != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	} else {
		si := protos.GetCluserListResponse{
			ClusterList: s,
		}
		c.JSON(
			200, &si,
		)
	}
}

func GetClusterInfo(c *gin.Context) {
	ServerName := c.Query("servername")

	req := &protos.GetServerInfoRequest{
		Servername: ServerName,
	}

	b, err := GetServerInfo(ServerName, req)
	if err != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	} else {
		s := protos.GetClusterInfoResponse{
			Servername:     ServerName,
			Cpu:            b.Cpu,
			Mem:            b.Mem,
			Alloc:          b.Alloc,
			Totalalloc:     b.Totalalloc,
			Sys:            b.Sys,
			HeapInuse:      b.HeapInuse,
			CpupercentList: b.CpupercentList,
		}
		c.JSON(
			200, &s,
		)
		return
	}
}

// func GetConnInfo(c *gin.Context) {
// 	values, err := Redis.SRandMemberN(c, ConnId_Redix_key, 100).Result()
// 	if err != nil {
// 		c.JSON(500, gin.H{
// 			"message": "服务器内部错误",
// 		})
// 		return
// 	} else {
// 		count, _ := Redis.SCard(c, ConnId_Redix_key).Result()
// 		// list<str> to list<Conn>
// 		var connList []*protos.Conn
// 		for _, str := range values {
// 			var conn protos.Conn
// 			if err := json.Unmarshal([]byte(str), &conn); err != nil {
// 				ZapLogger.Error(err)
// 				continue
// 			}
// 			connList = append(connList, &conn)
// 		}
// 		s := protos.GetConnInfoResponse{
// 			Total:    count,
// 			ConnList: connList,
// 		}
// 		c.JSON(
// 			200, &s,
// 		)
// 		return
// 	}
// }

func GetChannels(c *gin.Context) {
	values, err := Redis.SMembers(c, Channel_Redis_key).Result()

	if err != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	} else {
		s := protos.GetChannelsResponse{
			ChannelList: values,
		}
		c.JSON(
			200, &s,
		)
		return
	}
}

func GetChannelsCount(c *gin.Context) {
	servername := c.Query("servername")
	count, _ := Redis.Get(c, servername).Result()
	i, b := strconv.Atoi(count)
	if b != nil {
		c.JSON(500, gin.H{
			"message": "服务器内部错误",
		})
		return
	}
	c.JSON(
		200, &protos.GetConnInfoResponse{
			Total: int64(i),
		},
	)
}

type DeleteChannelMemberStruct struct {
	Channel   string `json:"channel"`
	Identitys string `json:"identitys"`
}
